package com.yy.micro.magic.core.context;

import com.yy.micro.magic.core.annotation.Filter;
import com.yy.micro.magic.core.annotation.Runner;
import com.yy.micro.magic.core.condition.Condition;
import com.yy.micro.magic.core.config.Content;
import com.yy.micro.magic.core.filter.FilterChain;
import com.yy.micro.magic.core.filter.MagicFilter;
import com.yy.micro.magic.core.processor.MagicProcessor;
import com.yy.micro.magic.core.result.runner.ResultRunner;
import com.yy.micro.magic.core.result.value.ValueStrategy;
import com.yy.micro.magic.core.strategy.RuleStrategy;
import com.yy.micro.magic.exception.MapException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

@Component
public class ComponentManager {

    @Autowired
    private MagicCubeContext context;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private Map<String, RuleStrategy> ruleStrategyMap;

    @Autowired
    private Map<String, MagicProcessor> processorMap;

    private Map<String, FilterChain> chains = new HashMap<>(8);

    private FilterChain _emptyHeader ;

    @Autowired(required = false)
    private List<MagicFilter> filters;

    @Resource(name = Content.STRATEGY_MAP_FILTER)
    private MagicFilter strategyFilter;

    @Autowired(required = false)
    private List<ResultRunner> runners;

    @Autowired
    private Map<String,RuleStrategy> ruleStrategies;

    @Autowired
    private List<ValueStrategy> valueStrategies;


    public MagicProcessor getProcessor(String name){
        if (null == processorMap || !processorMap.containsKey(name)){
            throw new MapException("Not find processor["+name+"]");
        }
        return processorMap.get(name);
    }

    public FilterChain getHeadFilterChain(String plan){
        if (chains.containsKey(plan)){
            return chains.get(plan);
        }else {
            if(null != filters && !filters.isEmpty()){
                FilterChain head = new FilterChain(null,null);
                FilterChain current = head;
                for (MagicFilter filter:filters){
                    if (filter != strategyFilter){
                        Filter f =filter.getClass().getAnnotation(Filter.class);
                        if (null != f){
                            boolean match = null ==f.planCodes() || f.planCodes().length <1 ||Arrays.stream(f.planCodes()).anyMatch(p-> p.equalsIgnoreCase(plan));
                            if (match){
                                if (head == current){
                                    current = new FilterChain(filter,null);
                                    head.setNext(current);
                                }else{
                                    FilterChain chain = new FilterChain(filter,null);
                                    current.setNext(chain);
                                    current = chain;
                                }
                            }
                        }
                    }
                }
                current.setNext(getEndFilterChain());
                chains.put(plan,head);
                return head;
            }
        }
        return getEmptyHeadFilterChain();
    }

    public RuleStrategy getRuleStrategy(String strategy){
        if (StringUtils.isEmpty(strategy)){
            strategy = Content.COPY_STRATEGY;
        }
        return ruleStrategies.get(strategy);
    }

    private FilterChain getEmptyHeadFilterChain(){
        if (null ==_emptyHeader){
            _emptyHeader = new FilterChain(getEndFilter(),null);
        }
        return _emptyHeader;
    }

    private FilterChain getEndFilterChain(){
        return new FilterChain(getEndFilter(),null);
    }

    private MagicFilter getEndFilter(){
        return strategyFilter;
    }

    public List<ValueStrategy> getValueStrategies() {
        return valueStrategies;
    }


    public List<ValueStrategy> getValueStrategies(int strategy){
        if (null != valueStrategies && !valueStrategies.isEmpty()){
            return valueStrategies.stream().filter(v-> v.support(strategy)).collect(Collectors.toList());
        }
        return Collections.EMPTY_LIST;
    }

    public List<ResultRunner> findResultRunners(String planCode){
        if (null != runners){
            return runners.stream().filter(r->{
                Runner runner=r.getClass().getAnnotation(Runner.class);
                String code =runner.planCode();
                if (!StringUtils.isEmpty(code)){
                    return code.equals(planCode);
                }else {
                    return doCondition(runner.condition(),planCode);
                }
            }).collect(Collectors.toList());
        }
        return Collections.EMPTY_LIST;
    }

    private boolean doCondition(Class<? extends Condition> cls , Object planCode){
        if (null != cls){
            Condition condition=applicationContext.getBean(cls);
            return condition.match(planCode);
        }
        return false;
    }
}
